/* ==================================================================   
 * Created [2009-4-27 下午11:32:55] by Jon.King 
 * ==================================================================  
 * TSS 
 * ================================================================== 
 * mailTo:jinpujun@hotmail.com
 * Copyright (c) Jon.King, 2009-2012 
 * ================================================================== 
 */

package com.jinhe.tss.cms.dao.impl;

import java.io.File;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.jinhe.tss.cms.CMSConstants;
import com.jinhe.tss.cms.dao.IArticleDao;
import com.jinhe.tss.cms.entity.Article;
import com.jinhe.tss.cms.entity.Attachment;
import com.jinhe.tss.cms.entity.ChannelArticle;
import com.jinhe.tss.cms.entity.ChannelArticleId;
import com.jinhe.tss.cms.helper.ArticleHelper;
import com.jinhe.tss.cms.helper.ArticleQueryCondition;
import com.jinhe.tss.component.support.persistence.pagequery.PageInfo;
import com.jinhe.tss.component.support.persistence.pagequery.PaginationQueryByHQL;
import com.jinhe.tss.core.exception.BusinessException;
import com.jinhe.tss.core.persistence.BaseDao;
import com.jinhe.tss.core.sso.Environment;
import com.jinhe.tss.core.util.EasyUtils;

/**
 * Article的Dao层，负责处理Article相关的数据库操作
 */
public class ArticleDao extends BaseDao<Article> implements IArticleDao {
    
    public ArticleDao() {
        super(Article.class);
    }
    
    public Article fetchArticleById(Long id) {
        Article article = getEntity( id );
        if(article == null){
            throw new BusinessException("文章不存在，可能已经被删除");
        }
        return article;
    }
 
    public Article saveArticle(Article article) {
        return create(article);
    }
    
    public Article renewArticle(Article article) {
        return create(article);
    } 

    public void deleteArticle(Article article) {
        Long articleId = article.getId();
        
        // 相关文章处理，注意查询条件为 或（or）
        String hql = "from ArticleLation o where o.id.articleId = ? or o.id.articleId = ?";
        deleteAll(getEntities(hql, articleId, articleId));

        //文章栏目关系删除
        deleteAll(getEntities("from ChannelArticle o where o.id.articleId = ?", articleId));
        
        //删除附件
        Map<String, Attachment> attachments = getArticleAttachments(articleId); // 后台查找的新建文章时上传的附件列表
        for ( Attachment attachment : attachments.values() ) {
            // 删除附件 TODO 如果是缩略图则还需删除原图片
            new File( ArticleHelper.getAttachUploadPath(article.getSite(), attachment)[0] ).delete();
           
            //删除老的附件信息
            super.delete(attachment);
        }
        
        // 删除文章生成的xml文件 （如果有的话）
        String pubUrl = article.getPubUrl();
        if ( !EasyUtils.isNullOrEmpty(pubUrl) ) {
            new File(pubUrl).delete(); 
        }
        
        super.delete(article);
    }
 
    public Integer getArticleLationNextOrder(Long articleId) {
        String hql = "select nvl(max(al.seqNo), 0) + 1 from ArticleLation al where al.id.articleId = ?";
        List<?> list = getEntities(hql, articleId);
        return (Integer) list.get(0);
    }
 
	public Integer getChannelArticleNextOrder(Long channelId) {
        String hql = "select nvl(max(ca.seqNo), 0) + 1 from ChannelArticle ca where ca.id.channelId = ?";
        List<?> list = getEntities(hql, channelId);
        return (Integer) list.get(0);
 	}
    
    public Integer getAttachmentNextOrder(Long articleId) {
        String hql = "select nvl(max(o.id.seqNo), 0) + 1 from Attachment o where o.id.articleId = ?";
        List<?> list = getEntities(hql, articleId);
        return (Integer) list.get(0);
    }
 
	public Map<String, Attachment> getArticleAttachments(Long articleId) {
        List<?> list = getEntities("from Attachment a where a.id.articleId = ?", articleId);
		Map<String, Attachment> map = new LinkedHashMap<String, Attachment>();
		for ( Object temp : list ) {
			Attachment attachment = (Attachment) temp;
			attachment.setUploadName(attachment.getRelationDownloadUrl()); //设置附件的下载地址
			map.put(attachment.getId().toString(), attachment);
		}
		return map;
	}

	public List<?> getPublishedArticleByChannel(Long channelId) {
		String hql = "select a.id, a.pubUrl, a.issueDate " +
				" from Article a, ChannelArticle ca, Channel c " +
				" where (a.deleted <> 1 or a.deleted is null)" +
                " and c.id = ca.id.channelId and ca.id.articleId = a.id" +
                " and ca.articleOrigin <> ? and a.status = ? and c.id = ?";
        return getEntities(hql, CMSConstants.ARTICLE_DISTRIBUTE, CMSConstants.XML_STATUS, channelId );
	}
 
	public ChannelArticle getChannelArticle(Long articleId, Long channelId) {
        ChannelArticleId id = new ChannelArticleId(channelId, articleId);
        return (ChannelArticle) getEntity(ChannelArticle.class, id);
	}
 
	public Long getChannelIdByArticleId(Long articleId) {
        String hql = "select t.id from Channel t, ChannelArticle ca"
            + " where t.id = ca.id.channelId  and ca.id.articleId = ? and ca.articleOrigin <> ?";
        List<?> list = getEntities(hql, articleId, CMSConstants.ARTICLE_DISTRIBUTE );
        Long channelId = list.size() > 0 ? (Long) list.get(0) : null;
        if( channelId == null ) {
            throw new BusinessException("找不到文章所在的栏目！");
        }
        
        return channelId;
	}
	
    public List<?> getDispathedToChannels(Long articleId) {
        String hql = "select distinct t from Channel t, ChannelArticle ca"
            + " where t.id = ca.id.channelId " 
            + " and ca.id.articleId = ? and ca.articleOrigin = ?";
        return getEntities(hql, articleId, CMSConstants.ARTICLE_DISTRIBUTE );
    }

	public List<?> getArticleLationsById(Long articleId) {
		String hql = "select a from ArticleLation lation, Article a "
				+ " where lation.id.articleId = ? and lation.id.lationArticleId = a.id and (a.deleted <> 1 or a.deleted is null)";
		return getEntities( hql, articleId );
	}
 
	public List<?> getLationsById(Long articleId) {
		return getEntities("from ArticleLation where id.articleId = ?", articleId);
	}
 
	public List<?> getFFChannelArticleListByArticle(Long articleId) {
		String hql = " from ChannelArticle ca where ca.id.articleId = ? and ca.articleOrigin = ?";
        return getEntities(hql, articleId, CMSConstants.ARTICLE_DISTRIBUTE);
	}
 
	public List<?> getZZChannelArticleList(Long articleId, Long channelId) {
		String hql = "from ChannelArticle ca where ca.sourceArticleId = ? and ca.sourceChannelId = ? and ca.articleOrigin = ?";
        return getEntities( hql, articleId, channelId, CMSConstants.ARTICLE_RESHIP );
	}
	
	// 以下两方法为全文检索时用到
    public boolean checkArticleWorkflowPermission(String operationId, Long resourceId) {
        if(resourceId == null) {
            resourceId = CMSConstants.DEFAULT_WORKFLOW_ID;
        }
        String hql = "select distinct v from RoleUserMapping r, WorkFlowPermissionsFull v " +
                " where v.id.resourceId= ? and v.id.roleId = r.id.roleId and r.id.userId = ? and v.id.operationId = ?";
        List<?> list = getEntities(hql, resourceId, Environment.getOperatorId(), operationId);
        return list.size() > 0 ;
    }

    @SuppressWarnings("unchecked")
	public List<Article> getExpireArticlePuburlList(Date now, Long channelId) {
        String hql = "select a from Article a, ChannelArticle ca " +
                " where a.id = ca.id.articleId and ca.id.channelId = ? and a.status = ? and a.overdueDate <= ? ";
        
        // 需要过期的文章为”已发布“状态的文章。其他状态没必要设置为过期
        return (List<Article>) getEntities(hql, channelId, CMSConstants.XML_STATUS, now);
    }
 
    //* *****************************************            for page search         ********************************************
    
	public PageInfo getPageList(Long channelId, Integer pageNum, String...orderBy) {
	    String hql = "select distinct a.id, a.title, a.author, a.articleTypeId, a.issueDate, a.wzrq, a.summary, "
				+ "     a.hitCount, a.creatorName, a.updatorName, a.createTime, a.updateTime,"
				+ "     a.status, ca.articleOrigin, ca.seqNo, c.id, ca.isTop, a.overdueDate, c.workflowId"
				+ " from Article a, ChannelArticle ca, Channel c"
				+ " where (a.deleted <> 1 or a.deleted is null)"
				+ " and ca.id.articleId = a.id and c.id = ca.id.channelId and c.id = :channelId ";
		
        ArticleQueryCondition condition = new ArticleQueryCondition();
        condition.setChannelId(channelId);
        condition.getPage().setPageNum(pageNum);
	        
        if(orderBy != null) {
            condition.getOrderByFields().addAll( Arrays.asList(orderBy) );
        } else {
            condition.getOrderByFields().add(" ca.seqNo desc ");  // 如果页面上不指定排序字段，默认按seqNo排序
        }
 
		PaginationQueryByHQL pageQuery = new PaginationQueryByHQL(em, hql, condition);
		return pageQuery.getResultList();
	}
	
	public PageInfo getSearchArticlePageList(ArticleQueryCondition condition) {
		String hql = "select distinct a.id, a.title, a.author, a.articleTypeId, a.issueDate, a.wzrq, a.summary,"
				+ "     a.hitCount, a.creatorName, a.updatorName, a.createTime, a.updateTime,"
				+ "     a.status, ca.articleOrigin, ca.seqNo, c.id, ca.isTop, a.overdueDate, c.workflowId " 
                + " from Article a, ChannelArticle ca, Channel c, Temp t"
				+ " where a.id = ca.id.articleId and ca.id.channelId = c.id and c.id = t.id "
				+ " ${excludeDeleted} ${author} ${status} ${title} ${searchDate}" ;
        
        String orderBy = condition.getOrderField() == null ? null : "a." + condition.getOrderField();
        if( orderBy != null && CMSConstants.TRUE.equals(condition.getIsDesc()) ) {
            orderBy += " desc ";
        }
        
        if(orderBy == null) {
            orderBy = " a.createTime desc "; // 如果页面上不指定排序字段，默认按文章的创建时间排序
        }
        condition.getOrderByFields().add(orderBy);
 
		PaginationQueryByHQL pageQuery = new PaginationQueryByHQL(em, hql, condition);
		return pageQuery.getResultList();
	}
 

	//* *****************************************  for portlet  ********************************************

    public List<?> getRelationArticles(Long articleId) {
        String hql = " select a from Article a, ArticleLation l  "
                + " where a.id = l.id.lationArticleId and l.id.articleId = ? and (a.deleted <> 1 or a.deleted is null) and a.status = ? " 
                + " order by a.createTime desc";
        return getEntities(hql, articleId, CMSConstants.XML_STATUS );
    }
     
    public PageInfo getChannelPageArticleList(ArticleQueryCondition condition) {
        String hql = "select distinct a.id, a.articleTypeId, a.title, a.author, a.summary, " 
                + "    a.issueDate, a.wzrq, a.createTime, a.hitCount, ca.isTop "
                + " from Article a, ChannelArticle ca, Channel c "
                + " where a.id = ca.id.articleId and ca.id.channelId = c.id " 
                + " ${channelId} ${status} ${excludeDeleted} "
                + " order by ca.isTop desc, a.createTime desc";
 
        PaginationQueryByHQL pageQuery = new PaginationQueryByHQL(em, hql, condition);
        return pageQuery.getResultList();
    }
    
    public PageInfo getArticlesByChannelIds(ArticleQueryCondition condition) {
        insertIds2TempTable(condition.getChannelIds());
        condition.setChannelIds(null);
 
        String hql = "select distinct a.id, a.title, a.author, a.createTime, a.wzrq, ca.isTop, a.summary, a.hitCount"
                    + " from Article a, ChannelArticle ca, Temp t"
                    + " where a.id = ca.id.articleId and ca.id.channelId = t.id" 
                    + " ${excludeDeleted} ${status} ${createTime} "
                    + " order by ca.isTop desc, a.createTime desc";
        
        PaginationQueryByHQL pageQuery = new PaginationQueryByHQL(em, hql, condition);
        return pageQuery.getResultList();
    }
}